//
// Created by Scave on 2023/11/13.
//

#include "ShaderProgram.h"
#include "Shader.h"
#include "bgfx/BgfxUtil.h"
#include "resource/Resource.h"

NS_RIDER_BEGIN

    ShaderProgram::ShaderProgram() = default;

    ShaderProgram::~ShaderProgram() {
        DESTROY_MEMBER_BGFX_HANDLE(program_handle_);
    }

    void ShaderProgram::Load(const unsigned char* vs_data,
                             uint16_t vs_data_len,
                             const unsigned char* fs_data,
                             uint16_t fs_data_len) {
        this->program_handle_ = loadProgramFromData(
                vs_data, vs_data_len, fs_data, fs_data_len);
    }

    void ShaderProgram::Load(const char* res_path, const char* vs_name, const char* fs_name) {
        this->program_handle_ = loadProgram(vs_name, fs_name, res_path);
    }

    void ShaderProgram::SetUniformV4(const String& name, float* data) {
        auto it = uniform_handle_map_.find(name);
        if (it == uniform_handle_map_.end()) {
            return;
        }
        bgfx::UniformHandle handle = it->second;
        bgfx::setUniform(handle, data);
    }

    void ShaderProgram::SetUniformV4Array(const String& name, void* data, UInt16 num_array) {
        auto it = uniform_handle_map_.find(name);
        if (it == uniform_handle_map_.end()) {
            return;
        }
        bgfx::UniformHandle handle = it->second;
        bgfx::setUniform(handle, data, num_array);
    }

    void ShaderProgram::SetUniformMat4(const String& name, float* data) {
        auto it = uniform_handle_map_.find(name);
        if (it == uniform_handle_map_.end()) {
            return;
        }
        bgfx::UniformHandle handle = it->second;
        bgfx::setUniform(handle, data, 16);
    }

    void ShaderProgram::SetTexture(const UInt8 stage, const String& name, Texture2D texture) {
        auto it = uniform_handle_map_.find(name);
        if (it == uniform_handle_map_.end()) {
            return;
        }
        bgfx::setTexture(stage, it->second, bgfx::TextureHandle{texture.GetId()});
    }

    MinimumShaderProgram::MinimumShaderProgram() {
        vertex_layout_
                .begin()
                .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
                .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
                .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Float)
                .end();
        this->Load(VS_MINIMUM, VS_MINIMUM_LEN, FS_MINIMUM, FS_MINIMUM_LEN);
    }

    StandardShaderProgram::StandardShaderProgram() {
        vertex_layout_
                .begin()
                .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
                .add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
                .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
                .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Float)
                .end();
        this->Load(VS_STANDARD, VS_STANDARD_LEN, FS_STANDARD, FS_STANDARD_LEN);
        uniform_handle_map_[TEXTURE_MAIN] = bgfx::createUniform(TEXTURE_MAIN, bgfx::UniformType::Enum::Sampler);
        uniform_handle_map_[TEXTURE_SPECULAR] = bgfx::createUniform(TEXTURE_SPECULAR, bgfx::UniformType::Enum::Sampler);
        uniform_handle_map_[UNIFORM_CAMERA_POSITION] = bgfx::createUniform(UNIFORM_CAMERA_POSITION, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_MATERIAL_PARAMS] = bgfx::createUniform(UNIFORM_MATERIAL_PARAMS, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_AMBIENT_COLOR] = bgfx::createUniform(UNIFORM_AMBIENT_COLOR, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_LIGHTS] = bgfx::createUniform(UNIFORM_LIGHTS, bgfx::UniformType::Enum::Vec4, MAX_LIGHTS * 6);
        uniform_handle_map_[UNIFORM_LIGHT_COUNT] = bgfx::createUniform(UNIFORM_LIGHT_COUNT, bgfx::UniformType::Enum::Vec4);
    }

    InstancingShaderProgram::InstancingShaderProgram() {
        vertex_layout_
                .begin()
                .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
                .add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
                .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
                .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Float)
                .end();
        this->Load(VS_INSTANCING, VS_INSTANCING_LEN, FS_INSTANCING, FS_INSTANCING_LEN);
        uniform_handle_map_[TEXTURE_MAIN] = bgfx::createUniform(TEXTURE_MAIN, bgfx::UniformType::Enum::Sampler);
        uniform_handle_map_[TEXTURE_SPECULAR] = bgfx::createUniform(TEXTURE_SPECULAR, bgfx::UniformType::Enum::Sampler);
        uniform_handle_map_[UNIFORM_CAMERA_POSITION] = bgfx::createUniform(UNIFORM_CAMERA_POSITION, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_MATERIAL_PARAMS] = bgfx::createUniform(UNIFORM_MATERIAL_PARAMS, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_AMBIENT_COLOR] = bgfx::createUniform(UNIFORM_AMBIENT_COLOR, bgfx::UniformType::Enum::Vec4);
        uniform_handle_map_[UNIFORM_LIGHTS] = bgfx::createUniform(UNIFORM_LIGHTS, bgfx::UniformType::Enum::Vec4, MAX_LIGHTS * 6);
        uniform_handle_map_[UNIFORM_LIGHT_COUNT] = bgfx::createUniform(UNIFORM_LIGHT_COUNT, bgfx::UniformType::Enum::Vec4);
    }

NS_RIDER_END
